package com.whut.monitor.netty.handler;

import com.whut.monitor.service.IHbaseService;
import com.whut.monitor.util.ProtocolUtil;
import com.whut.monitor.util.SendMessageUtil;
import com.whut.monitor.websocket.PollWebSocketServlet;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;

import static com.whut.monitor.netty.handler.ModelUpdateInboundHandler.getKeyByValueSingle;
import static com.whut.monitor.util.DateUtil.getNowTimeS;
import static com.whut.monitor.util.FileUtil.saveMap;
import static com.whut.monitor.util.HbaseUtil.hbaseSaveMapFilter;
import static com.whut.monitor.util.ProtocolUtil.*;
import static com.whut.monitor.util.WuzhongUtil.protocolParserBJ;
import static com.whut.monitor.util.WuzhongUtil.protocolParserXML;
import static com.whut.monitor.websocket.PollWebSocketServlet.CLIENTS;

/**
 * @author Sandeepin
 * 本类主要负责30s数据包推送前台与HBase存取
 */
@Service("ServerInboundHandler")
@Sharable
public class ServerInboundHandler extends SimpleChannelInboundHandler<String> {
    private static final Logger logger = Logger.getLogger(ServerInboundHandler.class);


    // 存Hbase，符合Hbase格式的Map，包括时间内所有的
    public static Map<String, String> hbaseSaveMap = new HashMap<>();
    // 存需要推向前台的传感器数据 监控编号-值
    public static Map<String, String> showSensorMap = new HashMap<>();
    // 存需要推向前台的机床数据 监控编号-值
    public static Map<String, String> showCncMap = new HashMap<>();

    // 之前机床包推向前台的时间
    public static long previousTimeShow = 0;
    // 通道监测映射
    public static Map<String, Channel> channelMap = new ConcurrentHashMap<>();
    // 存电类 监控编号-值
    public static Map<String, String> SDTMap = new HashMap<>();
    // 存环境温度  监控编号-值
    public static Map<String, String> SETMap = new HashMap<>();
    // 存FBG温度 监控编号-值
    public static Map<String, String> SFTMap = new HashMap<>();
    // 设备地址键值对
    public static Map<String, ChannelHandlerContext> packLinkMap = new HashMap<>();
    // FBG当前状态
    public static HashMap<Integer, Double> currentFBGDiagnosisMap = new HashMap<>();
    // FBG前一秒状态
    public static HashMap<Integer, Double> preFBGDiagnosisMap = new HashMap<>();
    // 一个FBG通道上的节点恒定（值不变）的次数   节点（1-90） -  恒值次数
    public static HashMap<Integer, Integer> constantCntFBG = new HashMap<>();
    // 模拟次数，记到10归零，重新
    public static int count = 1;
    // 90个传感器诊断标记 0是正常
    public static String showFBGDiagnosisContent = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
    // 制造的模拟数据
    public static Double[][] simulateValues = new Double[60][90];


    @Autowired
    PollWebSocketServlet webSocketServlet;
    @Autowired
    IHbaseService hbaseService;


    // 收到消息时 - 协议解析
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        long startTime = System.currentTimeMillis();
        if (msg.contains("@@,") && msg.contains("SDV,") && msg.contains("!!,")){
            // 大哥、蒋(BJ)版本协议解析
            protocolParserBJ(msg, hbaseSaveMap, showSensorMap, showCncMap, webSocketServlet, ctx);
        } else if(msg.contains("<whut>") && msg.contains("</whut>")){
            // XML版本协议解析
            protocolParserXML(msg, hbaseSaveMap, showSensorMap, showCncMap);
            showSensorMapToSDTSFTSETMap(showSensorMap, SDTMap, SFTMap, SETMap);
            virtualCNCDataShow(SDTMap, SFTMap, showCncMap, webSocketServlet);
        }
        String costTime = (System.currentTimeMillis() - startTime) / 1000.0 + "s";
        System.out.println("协议解析时间: "+costTime);
    }


    // 定时任务-推向前台-2s一次
    @Scheduled(cron = "0/2 * * * * ? ")
    public void taskCycleShowData2s() throws Exception {
        // 借助定时任务每天清空WebSocket客户端 每天晚上04:00:00、04:00:01、04:00:02
        String nowTime = getNowTimeS();
        if ("04:00:00".equals(nowTime.substring(11, 19)) ||
                "04:00:01".equals(nowTime.substring(11, 19)) ||
                "04:00:02".equals(nowTime.substring(11, 19))) {
            CLIENTS.clear();
        }
        // 传感器数据值
        for (String monitorNum : showSensorMap.keySet()) {
            String value = showSensorMap.get(monitorNum);
            SendMessageUtil.sendMessage(nowTime, monitorNum, value, webSocketServlet);
        }
        // 机床内部数据值
        for (String monitorNum : showCncMap.keySet()) {
            String value = showCncMap.get(monitorNum);
            SendMessageUtil.sendMessage(nowTime, monitorNum, value, webSocketServlet);
        }
//        saveMap("showSensorMap_RealTime_", showSensorMap, "");
//        saveMap("showCncMap_RealTime_", showCncMap, "");
    }

    // 定时任务-存hbase-【8s】一次，以保证10s抽样每时刻有值
    @Scheduled(cron = "0/8 * * * * ? ")
    public void taskCycleSaveHbase30s() throws Exception {
        long startTime = System.currentTimeMillis();

        // showMap(hbaseSaveMap);
        // 滤除老的时间键值对，保留最新版本
        Map<String, String> hbaseSaveMapFilted = hbaseSaveMapFilter(hbaseSaveMap);
        // 清空hbaseSaveMap，开始新一轮收集
        hbaseSaveMap.clear();
        // 对FBG数据进行波长对齐修复后再存
        for (String key : hbaseSaveMapFilted.keySet()) {
            if (key.length() > 5 && "ST".equals(key.substring(2, 4))) {
                hbaseSaveMapFilted.put(key, waveFixSST(hbaseSaveMapFilted.get(key)));
            }
            if (key.length() > 5 && "FT".equals(key.substring(2, 4))) {
                hbaseSaveMapFilted.put(key, waveFixSFT(hbaseSaveMapFilted.get(key)));
            }
        }
        // 存Hbase核心代码
        hbaseService.adds(hbaseSaveMapFilted);

        String costTime = (System.currentTimeMillis() - startTime) / 1000.0 + "s";
        saveMap("hbaseSaveMap_RealTime_", hbaseSaveMapFilted, costTime);
        // showMap(hbaseSaveMapFilted);
        //		logger.info("[show]showSensorMap:\n");
        //		showMap(showSensorMap);
        //		logger.info("[show]showCncMap:\n");
        //		showMap(showCncMap);
        //		logger.info("[show]SDTMap:\n");
        //		showMap(SDTMap);
        //		logger.info("[show]SFTMap:\n");
        //		showMap(SFTMap);
        //		logger.info("[show]SFTMap:\n");
        //		showMap(SFTMap);
    }

    // 定时任务-传感器诊断结果-90个FBG-1s一次
    @Scheduled(cron = "0/1 * * * * ? ")
    public void taskCycle1sFBGDiagnosis() throws Exception {
        // 借助定时任务初始化FBG转温度标定数据
        ProtocolUtil.initWaveMap();
        // 90个FBG诊断
        SendMessageUtil.sendMessageByWsj("wsj", showFBGDiagnosisContent, webSocketServlet);
    }

    // 通道打开时
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        logger.info("[poi]From:" + ctx.channel().remoteAddress() + " connect already OPEN!");
    }

    // 通道关闭时
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        logger.info("[poi]From:" + ctx.channel().remoteAddress() + " connect already CLOSE!");
        String backTip = getKeyByValueSingle(packLinkMap, ctx);
        if (backTip.indexOf("SDV") != -1) {
            // 【推向显示的大包数据清空】
            for (String monitorNum : showSensorMap.keySet()) {
                if (monitorNum.indexOf("SET") != -1) {
                    continue;
                }
                showSensorMap.put(monitorNum, "0.0");
            }
        } else if (backTip.indexOf("SET") != -1) {
            // 【推向显示的环境温度数据清空】
            for (String monitorNum : showSensorMap.keySet()) {
                if (monitorNum.indexOf("SET") != -1) {
                    showSensorMap.put(monitorNum, "0.0");
                }
            }
        } else if (backTip.indexOf("SCN") != -1) {
            // 【推向显示的机床数据清空】
            for (String monitorNum : showCncMap.keySet()) {
                // 4轴合并数据特殊处理
                if (monitorNum.length() > 6 && monitorNum.substring(4, 7).equals("POS")) {
                    showCncMap.put(monitorNum, "0,0,0,0");
                } else {
                    showCncMap.put(monitorNum, "0.0");
                }
            }
        }
    }

    // 异常
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        logger.info("[poi]From:" + ctx.channel().remoteAddress() + " connect ERROR!,cause=" + cause.getMessage());
        String backTip = getKeyByValueSingle(packLinkMap, ctx);
        if (backTip.indexOf("SDV") != -1) {
            // 【推向显示的大包数据清空】
            for (String monitorNum : showSensorMap.keySet()) {
                if (monitorNum.indexOf("SET") != -1) {
                    continue;
                }
                showSensorMap.put(monitorNum, "0.0");
            }
        } else if (backTip.indexOf("SET") != -1) {
            // 【推向显示的环境温度数据清空】
            for (String monitorNum : showSensorMap.keySet()) {
                if (monitorNum.indexOf("SET") != -1) {
                    showSensorMap.put(monitorNum, "0.0");
                }
            }
        } else if (backTip.indexOf("SCN") != -1) {
            // 【推向显示的机床数据清空】
            for (String monitorNum : showCncMap.keySet()) {
                // 4轴合并数据特殊处理
                if (monitorNum.length() > 6 && monitorNum.substring(4, 7).equals("POS")) {
                    showCncMap.put(monitorNum, "0,0,0,0");
                } else {
                    showCncMap.put(monitorNum, "0.0");
                }
            }
        }
    }

    private void addSocketChannel(String deviceNum, Channel channel) {
        channelMap.put(deviceNum, channel);
    }

    public Channel getSocketChannel(String deviceNum) {
        return channelMap.get(deviceNum);
    }

    public static void closeChannels() {
        for (Channel channel : channelMap.values()) {
            channel.close();
        }
    }
}